/****************************************************************************
 * (c) 2001 StreamBox Inc.  http://www.streambox.com/ 
 *
 * Division: Moscow Research Division
 * Project:  Tidy Scaling (video compression project)
 *
 * Contents: Filter-based scaling functions. Only ^2 scaling factor allowed.
 *           File contains 10-item fast filter implemntation.
 *
 * History:  26-Sep-2001 - Created by Smirnov K
 ****************************************************************************/
/**
 * \file scale_msk_f10_fast_mmx.c
 *  File contains 10-item fast filter implemntation. 
 *  Filter coeficients {3 -2 -12 14 61 61 14 -12 -2 3}
 *  Functions:
 *  void ScaleChannelUpX2Filter10_2VerticalMMX() 
 */ 


#include "../Lib/Scale_msk.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#ifdef _MMX_
#include <mmintrin.h>

/*============================= ScaleChannelUpX2Filter10_2VerticalMMX ==============================*/
/**
 * Scale UP Vertical Dimension of 2D channel using MMX. The Functon returns image sizes (w)x(2h)
 * The function operates with image dimensions more then 8*10
 *
 * \param in          [IN]  - pointer to input 2D channel
 * \param out         [OUT] - pointer to output 2D channel
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height
 * \retval - none
 */


void ScaleChannelUpX2Filter10_2VerticalMMX(BYTE* in, BYTE* out, int w, int h)
{
	int w_in = w, h_in = h, w_out = w_in, h_out = h<<1, h_end = h_in-4;
	int w_inmmx = w_in&3?((w_in>>2)+1):(w_in>>2);
    
	int i,c0,c1,c2,c3;
	BYTE* pIn, *pOut;

    const __m64 mmx_61 = _mm_set1_pi16(61);
    const __m64 mmx_14 = _mm_set1_pi16(14);
    const __m64 mmx__12 = _mm_set1_pi16(-12);
    const __m64 mmx__2 = _mm_set1_pi16(-2);
    const __m64 mmx_3 = _mm_set1_pi16(3);
    const __m64 mmx_32 = _mm_set1_pi16(32);

	pIn = in+w_in;
	pOut = out+w_out;

		for (i= 0; i<w_in; i++)
		{
			c0=pIn[i-w_in];
			c1=pIn[i];
			c2=pIn[i+w_in];
			c3=pIn[i+w_in*2];
			pOut[i-w_out]=  CLIP_F( (		  61*c0 + 14*c1 - 2*c2 + 36)/73 );
			pOut[i]=		CLIP_F( ( 14*c0 + 61*c1 - 12*c2 + 3*c3 + 33)/66 );
			pOut[i+w_out]=	CLIP_F( (-12*c0 + 61*c1 + 14*c2 - 2*c3 + 30)/61 );
		}


    __asm {
			pushad

			mov			edx, dword ptr [w_in]			//increment for next out[]/in[]
			mov			eax, edx
			neg			eax							// [-w_in]
			mov			ebx, dword ptr[h_end]

			movq		mm6, mmword ptr[mmx_32]
			pxor		mm5, mm5
loop_h:
            mov         esi, dword ptr [pIn]
            mov         edi, dword ptr [pOut]
			lea			esi, [esi+edx]
			lea			edi, [edi+edx*2]
            mov         dword ptr [pIn ], esi
            mov         dword ptr [pOut], edi

			mov			ecx, dword ptr [w_inmmx]			// horisonal counter 
										
loop_v4:
		//------------------------------------------------------
            movd		mm0, dword ptr [esi+eax*2]	//in[-w_in*2]
			punpcklbw	mm0, mm5// 
            movd		mm1, dword ptr [esi+eax]	//in[-w_in]
			punpcklbw	mm1, mm5// 
            movd		mm2, dword ptr [esi]		//in[0]
			punpcklbw	mm2, mm5// 
            movd		mm3, dword ptr [esi+edx]	//in[w_in]
			punpcklbw	mm3, mm5// 
            movd		mm4, dword ptr [esi+edx*2]	//[w_in*2]
			punpcklbw	mm4, mm5//

			pmullw		mm0, mmword ptr[mmx__2]		//*-2
			pmullw		mm1, mmword ptr[mmx_14]		//*14
			pmullw		mm2, mmword ptr[mmx_61]		//*61
			pmullw		mm3, mmword ptr[mmx__12]	//*-12
			pmullw		mm4, mmword ptr[mmx_3]		//*3
			paddsw		mm0, mm1
			paddsw		mm0, mm2
			paddsw		mm0, mm3			
			paddsw		mm0, mm4					//result1
			paddsw		mm0, mm6
			psraw		mm0, 6h
			packuswb	mm0, mm0					//4 bytes
			movd		dword ptr [edi], mm0		//save in out

            movd		mm0, dword ptr [esi+eax*2]	// repeat for second values
			punpcklbw	mm0, mm5// 
            movd		mm1, dword ptr [esi+eax]	
			punpcklbw	mm1, mm5// 
            movd		mm2, dword ptr [esi]
			punpcklbw	mm2, mm5// 
            movd		mm3, dword ptr [esi+edx]	
			punpcklbw	mm3, mm5// 
            movd		mm4, dword ptr [esi+edx*2]	
			punpcklbw	mm4, mm5//

			pmullw		mm0, mmword ptr[mmx_3]		
			pmullw		mm1, mmword ptr[mmx__12]	
			pmullw		mm2, mmword ptr[mmx_61]		
			pmullw		mm3, mmword ptr[mmx_14]		
			pmullw		mm4, mmword ptr[mmx__2]		
			paddsw		mm0, mm1
			paddsw		mm0, mm2
			paddsw		mm0, mm3					
			paddsw		mm0, mm4					//result2
			paddsw		mm0, mm6
			psraw		mm0, 6h
			packuswb	mm0, mm0					//4 bytes
			movd		dword ptr [edi+edx], mm0

			add			edi, 4h
			add			esi, 4h

			dec ecx
			jnz loop_v4

			dec	ebx
			jnz loop_h
			popad
			emms
       }
	
	pIn  += w_in;
	pOut += w_out*2*2;
	
		for(i=0; i<w_in; i++) 
		{
			c0=pIn[i-w_in*2];
			c1=pIn[i-w_in];
			c2=pIn[i];
			c3=pIn[i+w_in];
//		    c4=pIn[i+w_in*2]; // does not exist
			pOut[i-w_out*2]=	CLIP_F( (-2*c0 + 14*c1 + 61*c2 - 12*c3 + 30)/61 );
			pOut[i-w_out  ]=	CLIP_F( ( 3*c0 - 12*c1 + 61*c2 + 14*c3 + 33)/66 );
			pOut[i        ]=	CLIP_F( (-2*c1 + 14*c2 + 61*c3 + 36)/73 );
			pOut[i+w_out  ]=	CLIP_F( ( 3*c1 - 12*c2 + 61*c3 + 26)/52 );
			pOut[i+w_out*2]=	CLIP_F( (-2*c2 + 14*c3 + 61*c3 + 36)/73 );
		}

}

#endif /*MMX*/

